# tests/case/DWH_CS_086_parallel_test.py
# pytest tests/case/DWH_CS_086_parallel_test.py -n 5
import pytest
import logging
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, ElementClickInterceptedException, TimeoutException
from tests.utils import htmlUtils
from time import sleep


class Test_DWH_CS_086_Parallel:
    """数据可视化功能并行测试用例"""

    @pytest.mark.parametrize("username", ["user_01", "user_02", "user_03", "user_04", "user_05"])
    def test_parallel_chart_creation(self, config: dict, base_url: str, username: str):
        """并行创建图表测试 - 直接使用指定用户登录"""
        # 使用独立的浏览器实例管理
        from tests.conftest import run_browser
        driver = None
        try:
            # 为每个用户创建独立的浏览器实例
            driver = run_browser(config["browser_driver"]["driver"], config["browser_driver"]["driver_path"])

            # 直接使用指定用户登录，跳过默认的aaa用户
            password = config["users"][username]
            self.user_login(username, password, driver, base_url)

            # 执行测试步骤
            chart_name = f"Test_{username}"

            self.step1_navigate_to_visualization(driver)
            self.step2_create_new_chart(driver)
            self.step3_configure_chart(driver, chart_name)
            sleep(2)

            # 验证结果
            # assert self.check_chart_created(driver, chart_name)

        except Exception as e:
            logging.error(f"用户 {username} 测试失败: {e}")
            raise
        finally:
            # 确保资源清理
            if driver:
                try:
                    driver.quit()
                except Exception as e:
                    logging.error(f"关闭浏览器失败: {e}")

    def user_login(self, username: str, password: str, driver: WebDriver, base_url: str):
        """用户登录 - 不依赖全局配置"""
        logging.info(f"用户 {username} 开始登录")
        driver.get(base_url + "#/login")

        # 使用显式等待替代固定sleep
        wait = WebDriverWait(driver, 20)

        # 尝试多种方式定位用户名输入框
        username_element = None
        locators = [
            (By.XPATH, '//input[@type="text"]'),
            (By.XPATH, '//input[@placeholder="请输入用户名"]'),
            (By.CSS_SELECTOR, 'input[type="text"]')
        ]

        for by, locator in locators:
            try:
                username_element = wait.until(EC.presence_of_element_located((by, locator)))
                if username_element:
                    break
            except TimeoutException:
                continue

        if username_element is None:
            raise NoSuchElementException("无法定位用户名输入框")

        username_element.send_keys(username)

        # 定位密码输入框
        password_element = None
        password_locators = [
            (By.XPATH, '//input[@type="password"]'),
            (By.XPATH, '//input[@placeholder="请输入密码"]'),
            (By.CSS_SELECTOR, 'input[type="password"]')
        ]

        for by, locator in password_locators:
            try:
                password_element = wait.until(EC.presence_of_element_located((by, locator)))
                if password_element:
                    break
            except TimeoutException:
                continue

        if password_element is None:
            raise NoSuchElementException("无法定位密码输入框")

        password_element.send_keys(password)

        # 定位登录按钮
        login_button = None
        login_locators = [
            (By.XPATH, '//button[@type="button"]'),
            (By.XPATH, '//button[contains(text(), "登录")]'),
            (By.CSS_SELECTOR, 'button[type="button"]')
        ]

        for by, locator in login_locators:
            try:
                login_button = wait.until(EC.element_to_be_clickable((by, locator)))
                if login_button:
                    break
            except TimeoutException:
                continue

        if login_button is None:
            raise NoSuchElementException("无法定位登录按钮")

        login_button.click()

        # 等待登录完成，检查是否跳转到了首页或其他页面
        try:
            wait.until_not(EC.url_contains("#/login"))
        except TimeoutException:
            logging.warning("登录可能未成功完成")

        logging.info(f"用户 {username} 登录完成")

    def step1_navigate_to_visualization(self, driver: WebDriver):
        """导航到数据可视化页面"""
        wait = WebDriverWait(driver, 15)

        # 使用显式等待查找菜单项
        try:
            elements = wait.until(EC.presence_of_all_elements_located((By.TAG_NAME, 'li')))
        except TimeoutException:
            # 如果显式等待失败，回退到原始方法
            elements = htmlUtils.getElementsByTagName(driver, 'li')

        visualization_found = False
        for element in elements:
            try:
                # 使用text属性而不是accessible_name，提高兼容性
                if "数据可视化" in element.text:
                    # 确保元素可点击
                    WebDriverWait(driver, 10).until(EC.element_to_be_clickable(element))
                    element.click()
                    visualization_found = True
                    break
            except:
                continue

        if not visualization_found:
            raise Exception("未找到数据可视化菜单项")

        # 等待页面跳转
        try:
            wait.until(EC.url_contains("superset"))
        except TimeoutException:
            # 回退到原来的断言方式
            assert "superset" in driver.current_url, "未跳转到Superset页面"

    def step2_create_new_chart(self, driver: WebDriver):
        """创建新图表"""
        wait = WebDriverWait(driver, 15)

        # 等待页面加载完成
        try:
            wait.until(EC.presence_of_element_located((By.TAG_NAME, 'li')))
        except TimeoutException:
            sleep(3)  # 回退到固定等待

        # 点击"绘制图表"按钮
        nav_items = htmlUtils.getElementsByTagName(driver, 'li')
        chart_button_found = False
        for item in nav_items:
            try:
                if "绘制图表" in item.text:
                    # 增加滚动和等待
                    driver.execute_script("arguments[0].scrollIntoView(true);", item)
                    sleep(1)
                    # 等待元素可点击
                    WebDriverWait(driver, 10).until(EC.element_to_be_clickable(item))
                    item.click()
                    chart_button_found = True
                    break
            except:
                continue

        if not chart_button_found:
            raise Exception("未找到绘制图表导航项")

        # 等待iframe加载
        try:
            iframe = wait.until(EC.presence_of_element_located((By.XPATH, '//iframe')))
        except TimeoutException:
            sleep(5)  # 回退到固定等待
            iframe = htmlUtils.getElementByXPath(driver, '//iframe')

        driver.switch_to.frame(iframe)

        # 增强新建图表按钮定位逻辑
        chart_button = None
        chart_button_locators = [
            (By.XPATH,
             '//button[contains(@class, "antd5-btn-primary") and .//span[@class="anticon-plus"] and .//span[text()="图表"]]'),
            (By.XPATH, '//button[contains(@class, "primary") and .//span[text()="图表"]]'),
            (By.XPATH, '//button[.//span[text()="图表"]]'),
            (By.CSS_SELECTOR, 'button.ant-btn-primary'),
            (By.XPATH, '//button[contains(text(), "图表")]')
        ]

        # 增加重试机制
        for retry in range(3):
            for by, locator in chart_button_locators:
                try:
                    chart_button = wait.until(EC.element_to_be_clickable((by, locator)))
                    if chart_button:
                        break
                except TimeoutException:
                    continue
            if chart_button:
                break
            sleep(2)  # 等待后重试

        if chart_button is None:
            # 输出调试信息
            try:
                all_buttons = htmlUtils.getElementsByTagName(driver, 'button')
                logging.info(f"页面上找到 {len(all_buttons)} 个按钮")
                for i, btn in enumerate(all_buttons[:10]):  # 显示前10个按钮
                    try:
                        btn_text = btn.text
                        btn_class = btn.get_attribute('class')
                        logging.info(f"  按钮{i}: text='{btn_text}', class='{btn_class}'")
                    except:
                        pass
            except:
                pass
            raise Exception("未找到新建图表按钮")

        # 点击前确保元素可见且可点击
        driver.execute_script("arguments[0].scrollIntoView(true);", chart_button)
        sleep(1)

        # 使用JavaScript点击避免遮挡问题
        try:
            chart_button.click()
        except ElementClickInterceptedException:
            driver.execute_script("arguments[0].click();", chart_button)
        except Exception:
            driver.execute_script("arguments[0].click();", chart_button)

        # 等待下一步操作的元素出现
        try:
            wait.until(EC.presence_of_element_located((By.XPATH, '//input[@aria-label="数据集"]')))
        except TimeoutException:
            sleep(2)  # 回退到固定等待

        # 选择数据源 supplier
        datasource_select = None
        try:
            datasource_select = wait.until(EC.element_to_be_clickable((By.XPATH, '//input[@aria-label="数据集"]')))
        except TimeoutException:
            # 回退到重试机制
            for attempt in range(5):
                try:
                    datasource_select = htmlUtils.getElementByXPath(driver, '//input[@aria-label="数据集"]')
                    if datasource_select:
                        break
                    sleep(1)
                except:
                    sleep(1)

        if datasource_select is None:
            raise Exception("未找到数据集选择框")

        datasource_select.click()

        # 等待选项加载
        try:
            wait.until(EC.presence_of_element_located((By.XPATH, '//div[contains(text(), "dim_target_info")]')))
        except TimeoutException:
            sleep(1)

        supplier_options = None
        supplier_locators = [
            (By.XPATH, '//span[contains(@class, "css-l4488p") and text()="dim_target_info"]'),
            (By.XPATH, '//div[contains(text(), "dim_target_info")]'),
            (By.XPATH, '//span[text()="dim_target_info"]')
        ]

        for by, locator in supplier_locators:
            try:
                supplier_options = wait.until(EC.presence_of_all_elements_located((by, locator)))
                if supplier_options:
                    break
            except TimeoutException:
                continue

        if not supplier_options:
            raise Exception("未找到 supplier 数据源选项")

        # 确保元素可见并点击
        supplier_option = supplier_options[0]
        driver.execute_script("arguments[0].scrollIntoView(true);", supplier_option)
        sleep(1)
        try:
            supplier_option.click()
        except ElementClickInterceptedException:
            driver.execute_script("arguments[0].click();", supplier_option)
        except Exception:
            driver.execute_script("arguments[0].click();", supplier_option)

        # 等待下一步操作
        try:
            wait.until(
                EC.presence_of_element_located((By.XPATH, '//div[contains(@class, "viztype-label") and text()="表"]')))
        except TimeoutException:
            sleep(1)

        # 选择图表类型为表
        table_types = None
        try:
            table_types = wait.until(EC.presence_of_all_elements_located(
                (By.XPATH, '//div[contains(@class, "viztype-label") and text()="表"]')))
        except TimeoutException:
            # 回退到重试机制
            for attempt in range(5):
                try:
                    table_types = htmlUtils.getElementsByXPath(driver,
                                                               '//div[contains(@class, "viztype-label") and text()="表"]')
                    if table_types:
                        break
                    sleep(1)
                except:
                    sleep(1)

        if not table_types:
            raise Exception("未找到图表类型选项: 表")

        table_type = table_types[0]
        driver.execute_script("arguments[0].scrollIntoView(true);", table_type)
        sleep(1)
        try:
            table_type.click()
        except ElementClickInterceptedException:
            driver.execute_script("arguments[0].click();", table_type)
        except Exception:
            driver.execute_script("arguments[0].click();", table_type)

        # 等待下一步操作
        try:
            wait.until(EC.presence_of_element_located((
                By.XPATH, '//button[contains(@class, "antd5-btn-primary") and .//span[text()="创建新图表"]]')))
        except TimeoutException:
            sleep(1)

        # 点击创建新图表按钮
        create_buttons = None
        create_button_locators = [
            (By.XPATH, '//button[contains(@class, "antd5-btn-primary") and .//span[text()="创建新图表"]]'),
            (By.XPATH, '//button[.//span[contains(text(), "创建新图表")]]'),
            (By.XPATH, '//button[contains(@class, "primary") and contains(text(), "创建新图表")]'),
            (By.XPATH, '//button[contains(text(), "创建新图表")]')
        ]

        for by, locator in create_button_locators:
            try:
                create_buttons = wait.until(EC.presence_of_all_elements_located((by, locator)))
                if create_buttons:
                    break
            except TimeoutException:
                continue

        if not create_buttons:
            raise Exception("未找到创建新图表按钮")

        create_button = create_buttons[0]
        driver.execute_script("arguments[0].scrollIntoView(true);", create_button)
        sleep(1)
        try:
            create_button.click()
        except ElementClickInterceptedException:
            driver.execute_script("arguments[0].click();", create_button)
        except Exception:
            driver.execute_script("arguments[0].click();", create_button)

        # 切回主文档
        driver.switch_to.default_content()

        # 等待页面加载
        try:
            wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//iframe')))
            driver.switch_to.default_content()
        except TimeoutException:
            sleep(2)  # 回退到固定等待

    def step3_configure_chart(self, driver: WebDriver, chart_name: str):
        """配置图表参数"""
        wait = WebDriverWait(driver, 15)

        # 等待iframe加载并切换
        try:
            iframe = wait.until(EC.presence_of_element_located((By.XPATH, '//iframe')))
            driver.switch_to.frame(iframe)
        except TimeoutException:
            sleep(2)  # 回退到固定等待
            iframe = htmlUtils.getElementByXPath(driver, '//iframe')
            driver.switch_to.frame(iframe)

        try:
            # 填写图表名称
            name_input = None
            name_input_locators = [
                (By.XPATH, '//input[@aria-label="Chart title"]'),
                (By.XPATH, '//input[contains(@placeholder, "Add the name of the chart")]'),
                (By.CSS_SELECTOR, 'input.dynamic-title-input')
            ]

            for by, locator in name_input_locators:
                try:
                    name_input = wait.until(EC.presence_of_element_located((by, locator)))
                    if name_input:
                        break
                except TimeoutException:
                    continue

            if not name_input:
                raise Exception("未找到图表名称输入框")

            # 确保元素可见
            driver.execute_script("arguments[0].scrollIntoView(true);", name_input)
            sleep(1)

            # 使用JavaScript点击避免被遮挡
            driver.execute_script("arguments[0].click();", name_input)
            sleep(0.5)
            name_input.clear()
            name_input.send_keys(chart_name)
            from selenium.webdriver.common.keys import Keys
            name_input.send_keys(Keys.TAB)

            # 等待输入生效
            try:
                wait.until(EC.text_to_be_present_in_element_value((By.XPATH, '//input[@aria-label="Chart title"]'),
                                                                  chart_name))
            except TimeoutException:
                sleep(1)

            # 拖拽COUNT(*)指标
            left_count_metrics = None
            right_metric_dropzones = None

            metric_locators = [
                (By.XPATH, '//div[@draggable="true"]//span[contains(text(), "COUNT(*)")]'),
                (By.XPATH, '//span[contains(text(), "COUNT(*)")]')
            ]

            dropzone_locators = [
                (By.XPATH, '//div[contains(@class, "css-rnxy7r") and contains(text(), "将列/指标拖放到此处")]'),
                (By.XPATH, '//div[contains(text(), "将列/指标拖放到此处")]')
            ]

            # 查找指标元素
            for by, locator in metric_locators:
                try:
                    left_count_metrics = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if left_count_metrics:
                        break
                except TimeoutException:
                    continue

            # 查找放置区域
            for by, locator in dropzone_locators:
                try:
                    right_metric_dropzones = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if right_metric_dropzones:
                        break
                except TimeoutException:
                    continue

            if not (left_count_metrics and right_metric_dropzones):
                raise Exception("未找到指标元素或放置区域")

            from selenium.webdriver.common.action_chains import ActionChains
            source_element = left_count_metrics[0].find_element(By.XPATH, "./ancestor::div[@draggable='true']")
            target_element = right_metric_dropzones[0]

            driver.execute_script("arguments[0].scrollIntoView(true);", source_element)
            driver.execute_script("arguments[0].scrollIntoView(true);", target_element)
            sleep(1)

            actions = ActionChains(driver)
            actions.drag_and_drop(source_element, target_element).perform()

            # 等待拖拽完成
            try:
                wait.until(EC.presence_of_element_located((By.XPATH, '//div[contains(@class, "metric")]')))
            except TimeoutException:
                sleep(2)

            # 拖拽s_name维度
            left_s_name_columns = None
            right_dimension_dropzones = None

            dimension_locators = [
                (By.XPATH, '//div[@draggable="true"]//span[contains(text(), "energy_mode")]'),
                (By.XPATH, '//span[contains(text(), "energy_mode")]')
            ]

            dimension_dropzone_locators = [
                (By.XPATH, '//div[contains(@class, "css-rnxy7r") and contains(text(), "Drop columns here")]'),
                (By.XPATH, '//label[contains(text(), "Dimensions")]/following::div[contains(@class, "css-rnxy7r")]'),
                (By.XPATH, '//div[contains(text(), "Drop columns here")]')
            ]

            # 查找维度元素
            for by, locator in dimension_locators:
                try:
                    left_s_name_columns = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if left_s_name_columns:
                        break
                except TimeoutException:
                    continue

            # 查找维度放置区域
            for by, locator in dimension_dropzone_locators:
                try:
                    right_dimension_dropzones = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if right_dimension_dropzones:
                        break
                except TimeoutException:
                    continue

            if not (left_s_name_columns and right_dimension_dropzones):
                raise Exception("未找到维度元素或放置区域")

            source_element = left_s_name_columns[0].find_element(By.XPATH, "./ancestor::div[@draggable='true']")
            target_element = right_dimension_dropzones[0]

            driver.execute_script("arguments[0].scrollIntoView(true);", source_element)
            driver.execute_script("arguments[0].scrollIntoView(true);", target_element)
            sleep(1)

            actions = ActionChains(driver)
            actions.drag_and_drop(source_element, target_element).perform()

            # 等待拖拽完成
            try:
                wait.until(EC.presence_of_element_located((By.XPATH, '//div[contains(@class, "dimension")]')))
            except TimeoutException:
                sleep(1)

            # 点击create chart按钮
            create_buttons = None
            create_button_locators = [
                (By.XPATH, '//button[contains(@class, "antd5-btn-primary") and .//span[text()="Create chart"]]'),
                (By.XPATH, '//button[.//span[contains(text(), "Create chart")]]'),
                (By.XPATH, '//button[contains(@class, "primary") and contains(text(), "Create")]'),
                (By.XPATH, '//button[contains(text(), "Create chart")]')
            ]

            for by, locator in create_button_locators:
                try:
                    create_buttons = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if create_buttons:
                        break
                except TimeoutException:
                    continue

            if not create_buttons:
                raise Exception("未找到Create chart按钮")

            create_button = create_buttons[0]
            driver.execute_script("arguments[0].scrollIntoView(true);", create_button)
            sleep(1)
            try:
                create_button.click()
            except ElementClickInterceptedException:
                driver.execute_script("arguments[0].click();", create_button)
            except Exception:
                driver.execute_script("arguments[0].click();", create_button)

            # 等待图表创建完成
            try:
                wait.until(EC.presence_of_element_located((By.XPATH, '//div[contains(@class, "chart-container")]')))
            except TimeoutException:
                sleep(3)

            # 点击保存按钮
            save_buttons = None
            save_button_locators = [
                (By.XPATH, '//button[contains(@class, "superset-button-secondary") and .//span[text()="保存"]]'),
                (By.XPATH, '//button[@id="btn_modal_save" and contains(text(), "保 存")]'),
                (By.XPATH, '//button[contains(text(), "保存")]')
            ]

            for by, locator in save_button_locators:
                try:
                    save_buttons = wait.until(EC.presence_of_all_elements_located((by, locator)))
                    if save_buttons:
                        break
                except TimeoutException:
                    continue

            if save_buttons:
                save_button = save_buttons[0]
                driver.execute_script("arguments[0].scrollIntoView(true);", save_button)
                sleep(1)
                # 使用JavaScript点击避免被遮挡
                driver.execute_script("arguments[0].click();", save_button)

                # 等待模态框出现
                try:
                    wait.until(EC.presence_of_element_located((By.XPATH, '//input[@aria-label="选择看板"]')))
                except TimeoutException:
                    sleep(1)

                # 选择看板并保存
                try:
                    dashboard_select = None
                    try:
                        dashboard_select = wait.until(
                            EC.element_to_be_clickable((By.XPATH, '//input[@aria-label="选择看板"]')))
                    except TimeoutException:
                        # 回退到重试机制
                        for attempt in range(3):
                            try:
                                dashboard_select = htmlUtils.getElementByXPath(driver,
                                                                               '//input[@aria-label="选择看板"]')
                                if dashboard_select:
                                    break
                                sleep(1)
                            except:
                                sleep(1)

                    if dashboard_select:
                        dashboard_select.click()

                        # 等待选项加载
                        try:
                            wait.until(EC.presence_of_element_located((By.XPATH, '//div[@label="Test056"]')))
                        except TimeoutException:
                            sleep(1)

                        test086_options = None
                        try:
                            test086_options = wait.until(
                                EC.presence_of_all_elements_located((By.XPATH, '//div[@label="Test056"]')))
                        except TimeoutException:
                            # 回退到重试机制
                            for attempt in range(3):
                                try:
                                    test086_options = htmlUtils.getElementsByXPath(driver, '//div[@label="Test056"]')
                                    if test086_options:
                                        break
                                    sleep(1)
                                except:
                                    sleep(1)

                        if test086_options:
                            test086_option = test086_options[0]
                            driver.execute_script("arguments[0].scrollIntoView(true);", test086_option)
                            sleep(1)
                            try:
                                test086_option.click()
                            except ElementClickInterceptedException:
                                driver.execute_script("arguments[0].click();", test086_option)
                            except Exception:
                                driver.execute_script("arguments[0].click();", test086_option)

                            # 等待保存按钮可用
                            try:
                                wait.until(EC.element_to_be_clickable((By.XPATH, '//button[@id="btn_modal_save"]')))
                            except TimeoutException:
                                sleep(1)

                            modal_save_buttons = None
                            modal_save_locators = [
                                (By.XPATH, '//button[@id="btn_modal_save"]'),
                                (By.XPATH,
                                 '//button[contains(@class, "superset-button-primary") and contains(text(), "保 存")]'),
                                (By.XPATH, '//button[contains(text(), "保 存")]')
                            ]

                            for by, locator in modal_save_locators:
                                try:
                                    elements = wait.until(EC.presence_of_all_elements_located((By.TAG_NAME, 'button')))
                                    for btn in elements:
                                        try:
                                            if "保 存" in btn.text and "primary" in (btn.get_attribute('class') or ''):
                                                modal_save_buttons = [btn]
                                                break
                                        except:
                                            continue
                                    if modal_save_buttons:
                                        break
                                except TimeoutException:
                                    continue

                            if modal_save_buttons:
                                modal_save_button = modal_save_buttons[0]
                                driver.execute_script("arguments[0].scrollIntoView(true);", modal_save_button)
                                sleep(1)
                                try:
                                    modal_save_button.click()
                                except ElementClickInterceptedException:
                                    driver.execute_script("arguments[0].click();", modal_save_button)
                                except Exception:
                                    driver.execute_script("arguments[0].click();", modal_save_button)

                                # 等待保存完成
                                try:
                                    wait.until_not(
                                        EC.presence_of_element_located((By.XPATH, '//button[@id="btn_modal_save"]')))
                                except TimeoutException:
                                    sleep(2)
                            else:
                                raise Exception("未找到模态框保存按钮")
                        else:
                            raise Exception("未找到Test086看板选项")
                except Exception as e:
                    logging.warning(f"保存过程中出现异常: {e}")
                    pass

            else:
                raise Exception("未找到保存按钮")

        finally:
            # 确保总是切回主内容
            try:
                driver.switch_to.default_content()
            except:
                pass

    def check_chart_created(self, driver: WebDriver, chart_name: str) -> bool:
        """验证图表是否创建成功"""
        try:
            # 切回主文档上下文
            try:
                driver.switch_to.default_content()
            except:
                pass

            wait = WebDriverWait(driver, 10)

            # 检查URL
            if "chart" in driver.current_url and "new" not in driver.current_url:
                return True

            # 检查是否存在包含图表名称的元素
            try:
                chart_elements = wait.until(
                    EC.presence_of_all_elements_located((By.XPATH, f'//h1[contains(text(), "{chart_name}")]')))
                if len(chart_elements) > 0:
                    return True
            except TimeoutException:
                pass

            # 检查是否存在图表容器
            try:
                chart_containers = wait.until(
                    EC.presence_of_all_elements_located((By.XPATH, '//div[contains(@class, "chart-container")]')))
                if len(chart_containers) > 0:
                    return True
            except TimeoutException:
                pass

            return False
        except Exception as e:
            logging.error(f"验证图表创建失败: {e}")
            return False
